/*
 *  Copyright 2012 The WebRTC Project Authors. All rights reserved.
 *
 *  Use of this source code is governed by a BSD-style license
 *  that can be found in the LICENSE file in the root of the source
 *  tree. An additional intellectual property rights grant can be found
 *  in the file PATENTS.  All contributing project authors may
 *  be found in the AUTHORS file in the root of the source tree.
 */

#ifndef WEBRTC_CONDUCTOR_H_
#define WEBRTC_CONDUCTOR_H_

#include <deque>
#include <map>
#include <memory>
#include <set>
#include <string>

#include "peer_connection_client.h"
#include "main_window.h"
#include "data_channel_handler.h"
#include "config_parser.h"
#include "webrtc/api/mediastreaminterface.h"
#include "webrtc/api/peerconnectioninterface.h"

 // For unit tests.
FOWARD_DECLARE(EndToEndTests, SingleClientToServer);
FOWARD_DECLARE(EndToEndTests, DISABLED_SingleClientToServer);
FOWARD_DECLARE(EndToEndTests, ServerToClientLatency);
FOWARD_DECLARE(EndToEndTests, DISABLED_ServerToClientLatency);
FOWARD_DECLARE(EndToEndTests, MultiClientsToServer);
FOWARD_DECLARE(EndToEndTests, DISABLED_MultiClientsToServer);

namespace webrtc
{
	class VideoCaptureModule;
}

namespace cricket
{
	class VideoRenderer;
}

class Conductor : public webrtc::PeerConnectionObserver,
	public webrtc::CreateSessionDescriptionObserver,
    public PeerConnectionClientObserver,
	public MainWindowCallback,
	public DataChannelCallback
{
public:
	enum CallbackID 
	{
		MEDIA_CHANNELS_INITIALIZED = 1,
		PEER_CONNECTION_CLOSED,
		SEND_MESSAGE_TO_PEER,
		NEW_STREAM_ADDED,
		STREAM_REMOVED,
	};

	Conductor(
		PeerConnectionClient* client,
		MainWindow* main_window,
		StreamingToolkit::WebRTCConfig* webrtc_config);

	bool connection_active() const;

	void SetTurnCredentials(const std::string& username, const std::string& password);

	void StartLogin(const std::string& server, int port) override;

	void ConnectToPeer(int peer_id) override;

	virtual void Close();

protected:
	~Conductor();

	bool InitializePeerConnection();

	bool ReinitializePeerConnectionForLoopback();

	bool CreatePeerConnection(bool dtls);

	void DeletePeerConnection();

	void EnsureStreamingUI();

	void AddStreams();

	//-------------------------------------------------------------------------
	// PeerConnectionObserver implementation.
	//-------------------------------------------------------------------------

	void OnSignalingChange(
		webrtc::PeerConnectionInterface::SignalingState new_state) override {};

	void OnAddStream(
		rtc::scoped_refptr<webrtc::MediaStreamInterface> stream) override;

	void OnRemoveStream(
		rtc::scoped_refptr<webrtc::MediaStreamInterface> stream) override;

	void OnDataChannel(
		rtc::scoped_refptr<webrtc::DataChannelInterface> channel) override;

	void OnRenegotiationNeeded() override {};

	void OnIceConnectionChange(
		webrtc::PeerConnectionInterface::IceConnectionState new_state) override;

	void OnIceGatheringChange(
		webrtc::PeerConnectionInterface::IceGatheringState new_state) override {};

	void OnIceCandidate(const webrtc::IceCandidateInterface* candidate) override;

	void OnIceConnectionReceivingChange(bool receiving) override {}

	//-------------------------------------------------------------------------
	// PeerConnectionClientObserver implementation.
	//-------------------------------------------------------------------------

	void OnSignedIn() override;

	void OnDisconnected() override;

	void OnPeerConnected(int id, const std::string& name) override;

	void OnPeerDisconnected(int id) override;

	void OnMessageFromPeer(int peer_id, const std::string& message) override;

	void OnMessageSent(int err) override;

	void OnHeartbeat(int heartbeat_status) override;

	void OnServerConnectionFailure() override;

	//-------------------------------------------------------------------------
	// MainWndCallback implementation.
	//-------------------------------------------------------------------------

	void DisconnectFromServer() override;

	void DisconnectFromCurrentPeer() override;

	void UIThreadCallback(int msg_id, void* data) override;

	// DataChannelCallback implementation.
	bool SendInputData(const std::string& message) override;

	// CreateSessionDescriptionObserver implementation.
	void OnSuccess(webrtc::SessionDescriptionInterface* desc) override;

	void OnFailure(const std::string& error) override;

protected:
	// Send a message to the remote peer.
	void SendMessage(const std::string& json_object);

	int peer_id_;
	bool loopback_;
	rtc::scoped_refptr<webrtc::PeerConnectionInterface> peer_connection_;
	rtc::scoped_refptr<webrtc::PeerConnectionFactoryInterface>
		peer_connection_factory_;

	PeerConnectionClient* client_;
	rtc::scoped_refptr<webrtc::DataChannelInterface> data_channel_;
	MainWindow* main_window_;
	StreamingToolkit::WebRTCConfig* webrtc_config_;
	std::deque<std::string*> pending_messages_;
	std::map<std::string, rtc::scoped_refptr<webrtc::MediaStreamInterface>>
		active_streams_;

	std::string server_;
	std::string turn_username_;
	std::string turn_password_;

	webrtc::PeerConnectionInterface::IceConnectionState ice_state_;

	// For unit tests.
	FRIEND_TEST(EndToEndTests, SingleClientToServer);
	FRIEND_TEST(EndToEndTests, DISABLED_SingleClientToServer);
	FRIEND_TEST(EndToEndTests, ServerToClientLatency);
	FRIEND_TEST(EndToEndTests, DISABLED_ServerToClientLatency);
	FRIEND_TEST(EndToEndTests, MultiClientsToServer);
	FRIEND_TEST(EndToEndTests, DISABLED_MultiClientsToServer);
};

#endif // WEBRTC_CONDUCTOR_H_
